Hate Speech auf Twitter

Textanalyse
Klassifikation
Huggingface
Python
tidymodels
Author

Raphael Balzer, Matr.Nr.: 00163021

Published

February 6, 2024

1 Einleitung

Ziel dieses Posts ist es, Hate Speech auf Twitter zu klassifizieren. Hass im Internet ist nach wie vor ein großes gesellschaftliches Problem, weshalb es sich lohnt, genauer zu untersuchen, was diesen Hass ausmacht und wie man ihn zuverlässig und automatisiert erkennen kann. Hierfür liegt ein Datensatz vor, der eine Auswahl englischer als Hate Speech oder nicht Hate Speech markierter Tweets enthält. Die Analyse dieser Daten lässt sich in zwei Teile gliedern: Zunächst werden Methoden der explorativen Datenanalyse angewandt, um Muster und Auffälligkeiten in den Tweets zu identifizieren. Anschließend werden die gewonnenen Erkenntnisse genutzt, um sowohl Shallow-Learning- als auch Deep-Learning-Algorithmen darauf zu trainieren, Tweets korrekterweise als Hate Speech einzuordnen.

1.1 Vorbereitung

1.1.1 Pakte laden

library(tidymodels)
library(textrecipes)
library(tokenizers)
library(tidyverse)
library(ggraph)
library(igraph)
library(tidytext)
library(syuzhet)
library(textdata)
library(ggthemes)
library(topicmodels)
library(tm)
library(stringr)
library(readr)
library(vip)

1.1.2 Datenimport

Bei den Daten handelt es sich um eine Auswahl englischer Tweets, die bereits auf Hate Speech untersucht wurden und sich daher gut für das Training von Modellen zur Erkennung von Hassrede eignen.

d_hate <- read_csv("d_hate.csv")

2 Explorative Datenanalyse

Ziel ist es, auf Grundlage der Tweets einige nützliche Features zu generieren, die sich als Prädiktor für die AV (Hatespeech oder nicht) eignen. Hierfür müssen zunächst einige Charakteristika von Tweets, die als Hate Speech gelten, herausgearbeitet werden. Die Methoden und der Code orientieren sich stark an dem Vorgehen, das in Julia Silges und David Robinsons Buch “Text Mining with R” beschrieben wird. Für die nachfolgenden Visualisierungen wird eine mit Hilfe der Seite https://davidmathlogic.com/colorblind eigens erstellte Farbpalette verwendet, die gewährleistet, dass keine Art der Farbenblindheit die Lesbarkeit der Diagramme beeinträchtigt.

Uriah_Flint <- c("#8175AA", "#6FB899", "#3AA2C3", "#8BD4F9", "#DDCC77", "#CC6677", "#882255")

2.1 Vorverarbeitung

Um eine sinnvolle Analyse durchzuführen, müssen noch einige Datenvorverarbeitungsschritte durchlaufen werden. Diese beinhalten die Tokenisierung, das Entfernen von Stopwords und das Bereinigen der Tweets, die Links oder ähnliche Elemente enthalten.

d_hate_clean <- d_hate %>%
  mutate(tweet = str_remove_all(tweet, pattern = 'RT\\s*|http[s]?://\\S+|\\d+'))

set.seed(123)
train_test_split <- initial_split(d_hate_clean, prop = .8, strata = class)
d_train <- training(train_test_split)
d_test <- testing(train_test_split)

2.1.1 Tokenisierung

tweets_token <- d_train %>%
  unnest_tokens(word, tweet)

2.1.2 Entfernung der Stopwords

data(stopwords_en, package = "lsa")
stopwords_en <- tibble(word = stopwords_en)

tweets_token <- tweets_token %>%
  anti_join(stopwords_en)
Joining with `by = join_by(word)`

2.1.3 Sentimentwerte

senti <- get_sentiments("afinn") %>% 
  mutate(neg_pos = case_when(value > 0 ~ "pos",
                             TRUE ~ "neg"))

tweets_senti <- tweets_token %>%
inner_join(senti)
Joining with `by = join_by(word)`

2.2 Anteil von Hate Speech

Um sich einen ersten Überblick über die Daten zu verschaffen, ist es sinnvoll, zunächst einmal den Anteil der als Hate Speech markierten Tweets zu überprüfen.

tweets_token %>% 
  summarise(`Anteil Hate Speech` = mean(class == "hate speech")) %>% 
  round(2)
class_totals <- tweets_token %>%
  count(class, name = "class_total")

ggplot(class_totals, aes(x = "", y = class_total, fill = class)) +
  geom_bar(stat = "identity") +
  labs(title = "Anteil an Hate Speech",
       x = NULL,
       y = NULL,
       fill = "Klasse") +
  geom_text(aes(label = class_total), position = position_stack(vjust = 0.5)) +
  theme_light() +
  scale_fill_manual(values = Uriah_Flint)

Der Anteil der Hate Speech in diesem Datensatz beträgt 25 Prozent. Die Tweets anderer Kategorien sind also deutlich in der Mehrheit.

2.3 Worthäufigkeiten

Einen weiteren interessanten Einblick gewähren die Worthäufigkeiten. Durch die Visualisierung der am meisten verwendeten Wörter und Wortpaare ist es bereits möglich, einen Einblick in das Vokabular zu erhalten und dieses unter den Klassen zu vergleichen.

tweets_count_senti <- tweets_senti %>%
  group_by(class) %>% 
  count(class, word, sort = TRUE) %>% 
  slice_head(n = 10)

word_counts <- left_join(tweets_count_senti, class_totals, by = "class")

# Berechnung der gewichteten Häufigkeit
word_counts <- word_counts %>%
  mutate(weighted_frequency = n / class_total)

# Visualisierung der gewichteten Häufigkeiten
ggplot(word_counts, aes(x = reorder(word, weighted_frequency), y = weighted_frequency, fill = class)) +
  geom_bar(stat = "identity") +
  facet_wrap(~class, scales = "free_y") +
  coord_flip() +
  labs(title = "Gewichtete Häufigkeiten der Wörter in Abhängigkeit von der Klasse",
       x = "Wort",
       y = "Gewichtete Häufigkeit") +
  theme_light() +
  scale_fill_manual(values = Uriah_Flint)

Beim Vergleich der häufigsten Wörter fällt direkt auf, dass Beleidigungen und Schimpfwörter charakteristisch für Hate Speech sind, da die Liste der zehn häufigsten Wörter fast nur aus solchen Einträgen besteht. Das Vokabular der anderen Kategorie ist im Vergleich dazu überaus harmlos. Diese Harmlosigkeit wird durch das häufigste Wort “lol” noch auf die Spitze getrieben. Interessant ist jedoch auch, dass sich das Wort “hate” in dieser Liste wiederfindet. Hier wäre es interessant, im weiteren Verlauf der Analyse den Kontext in Erfahrung zu bringen. Auf der anderen Seite ist “hate” jedoch ein sehr gängiges Wort und dient zur Beschreibung normaler Gefühlszustände, ohne direkt Hass zu verbreiten.

tweets_bigram <- 
  d_train %>%
  unnest_tokens(bigram, tweet, token = "ngrams", n = 2) %>%
  filter(!is.na(bigram))

tweets_bigram <- tweets_bigram %>%
  separate(bigram, c("word1", "word2"), sep = " ")%>%
  filter(!word1 %in% stop_words$word) %>%
  filter(!word2 %in% stop_words$word)

tweets_bigram %>%
  unite(bigram, word1, word2, sep = " ") %>%
  group_by(class) %>% 
  count(bigram, sort = TRUE) %>%
  slice_max(n, n = 10) %>%
  mutate(bigram = reorder(bigram, n)) %>%
  ggplot(aes(n, bigram, fill = class) ) +
  facet_wrap(~class, scales = "free_y") +
  geom_col() +
  labs(title = "Bigramme nach Häufigkeit",
       x = "Häufigkeit",
       y = "Bigramm") +
  scale_fill_manual(values = Uriah_Flint) +
  theme_light()

Die Analyse der häufigsten Wortpaare deckt sich mit der Analyse der häufigsten Wörter. Sie bringt insofern neue Erkenntnisse, als deutlich wird, dass sich der Hass hauptsächlich gegen ethnische und sexuelle Minderheiten richtet. Dies wird anhand von Begriffen wie “white trash” und “fucking faggot” deutlich. Bemerkenswert ist ebenfalls, dass es sich keinesfalls hauptsächlich um Hass gegen Schwarze handelt, sondern genauso auch Menschen mit heller Hautfarbe ethnisch beleidigt werden.

2.4 Wortbeziehungen

Im Folgenden werden alle Wortpaare, die häufiger als sechs Mal vorkommen, visualisiert. Hierdurch werden die Kontexte der Wörter deutlicher und die Beziehungen können uns Aufschluss darüber geben, in welchem Zusammenhang “hate” verwendet wird.

tweets_bigram_count <- tweets_bigram %>% 
   count(word1, word2, sort = TRUE)

visualize_bigrams <- function(bigrams) {
  set.seed(2016)
  a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
  
  bigrams %>%
    graph_from_data_frame() %>%
    ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), show.legend = FALSE, arrow = a) +
    geom_node_point(color = "#6FB899", size = 5) +
    geom_node_text(aes(label = name), vjust = 1, hjust = 1) +
    theme_void()
}

tweets_bigram_count %>%
  filter(n > 6,
         !str_detect(word1, "\\d"),
         !str_detect(word2, "\\d")) %>%
  visualize_bigrams()
Warning: Using the `size` aesthetic in this geom was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` in the `default_aes` field and elsewhere instead.

Zum Kontext des Wortes “hate” erhalten wir hier keine neuen Hinweise. Jedoch wird klar ersichtlich, in welchen Kombinationen Schimpfwörter verwendet werden. Außerdem werden Ambiguitäten deutlich, da Wörter wie “trash” und “colored” sowohl als rassistische Beleidigung als auch als Beschreibung von Alltagsgegenständen auftauchen.

2.5 Sentimentanalyse

Zweck der Sentimentanalyse ist es, herauszufinden, ob die Sentimentausprägungen die beiden Klassen klar voneinander abgrenzen.

# Zählen der negativen und positiven Sentimente
tweets_senti2 <- tweets_senti %>% 
  group_by(class) %>% 
  count(neg_pos, name = "count")

# Visualisierung der Sentimentantanteile nach Klasse
ggplot(tweets_senti2, aes(x = "", y = count, fill = neg_pos)) +
  geom_bar(stat = "identity") +
  labs(title = "Sentimentanteile nach Klasse",
       x = NULL,
       y = NULL,
       fill = "Sentiment") +
  facet_wrap(~ class) +
  geom_text(aes(label = count), position = position_stack(vjust = 0.5)) +
  theme_light() +
  scale_fill_manual(values = Uriah_Flint)

In obigem Diagramm wird ersichtlich, dass hasslastige Tweets überwiegend negativ sind, während sich die Sentimente der anderen Klasse in der Waage halten. Das Sentiment ist also ein entscheidender Faktor bei der Klassifizierung von Hate Speech und sollte beim Training des Modells berücksichtigt werden.

2.6 Themenanalyse

Die Themenanalyse soll Aufschluss darüber geben, ob es bestimmte Themengebiete gibt, die charakteristisch für Hate Speech sind.

tweets_token_counts_hate <- tweets_token %>%
  filter(class == "hate speech") %>% 
  count(word, sort = TRUE) %>%
  filter(n > 19) %>% 
  select(word)

tweets_dtm_hate <- DocumentTermMatrix(tweets_token_counts_hate)
tweets_dtm_hate
tweets_lda_hate <- LDA(tweets_dtm_hate, k = 4, control = list(seed = 42))

tweets_themen_hate <- tidy(tweets_lda_hate, matrix = "beta")

tweets_themen_hate <- tweets_themen_hate %>%
  group_by(topic) %>%
  slice_max(beta, n = 7) %>% 
  ungroup() %>%
  arrange(topic, -beta)

tweets_themen_hate %>%
  mutate(term = reorder_within(term, beta, topic)) %>%
  ggplot(aes(beta, term, fill = factor(topic))) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ topic, scales = "free") +
  scale_y_reordered() +
  labs(title = "Themen von Hate Speech") +
  theme_minimal() +
  scale_fill_manual(values = Uriah_Flint)

Obwohl sich die Themen nicht eindeutig voneinander abgrenzen, sind dennoch schwache Muster erkennbar. Thema Eins scheint sich vor allem aus allgemeinen Obszönitäten zusammenzusetzen, während das zweite Thema aus Beleidigungen gegen Schwule und Schwarze und etwas härteren Wörtern wie “kill” und “shit” besteht. In Thema Drei und Vier treten Beleidigungen gegen Frauen sowie die LGBTQ-Community in den Vordergrund. Viel wichtiger als diese kleinen Unterschiede ist jedoch das große Bild der Themen, welches wie schon bei der Analyse der Worthäufigkeiten festgestellt, hauptsächlich aus ethnischen und sexuellen Beleidigungen und Schimpfwörtern besteht.

2.7 Schimpfwörter

Schimpfwörter scheinen eine große Rolle bei Hate Speech zu spielen. Deshalb erachte ich es als sinnvoll, Schimpfwörter als Feature in das spätere Rezept mit aufzunehmen. Hierzu verwende ich diese Liste, welche ich um ein paar Einträge (rassistische Beleidigungen) ergänzt habe: https://www.insult.wiki/list-of-insults.

insults <- read.csv("insults.csv")

tweets_token %>%
  group_by(class) %>% 
  count(word, sort = TRUE) %>% 
  left_join(insults, by = "word") %>% 
  mutate(insult = case_when(is.na(value) == TRUE ~ "Nein",
                            TRUE ~ "Ja")) %>% 
  select(-value) %>% 
ggplot(aes(x = "", y = n, fill = insult)) +
  geom_bar(stat = "identity") +
  labs(title = "Anteil der Beleidigungen nach Klasse",
       x = NULL,
       y = NULL,
       fill = "Beleidigung") +
  facet_wrap(~ class, scales = "free_y") +
  theme_light() +
  scale_fill_manual(values = Uriah_Flint)

Tatsächlich ist der Anteil der Beleidigungen in Hate Speech Tweets höher, jedoch fällt er deutlich geringer aus als erwartet.

2.8 Emojis

Die Überlegung, dass Hate Speech feindselige Emojis enthält, ist sehr plausibel. Um aggressive Emojis zu kennzeichnen, verwende ich ein von mir erstelltes Lexikon, das solche Emojis enthält und schreibe eine Funktion, die zählt, wieviele feindselige Emojis in einem Tweet vorkommen. Der Totenkopf ist nicht in der Liste der feindseligen Emojis enthalten, da dieser hauptsächlich als Synonym oder Steigerung des Lach-Emojis verwendet wird (engl.: “That’s too funny. I’m dead!”).

hostile_emojis <- read.csv("hostile_emojis.csv")
count_hostile_emojis <- function(text) {
  # Initialisiere einen leeren Vektor für die Zählungen
  counts <- numeric(length(hostile_emojis$emoji))

  # Iteriere über jedes Emoji und zähle die Übereinstimmungen im Text
  for (i in seq_along(hostile_emojis$emoji)) {
    counts[i] <- sum(lengths(str_extract_all(text, hostile_emojis$emoji[i])))
  }

  # Summiere die Gesamtanzahl der Übereinstimmungen
  total_count <- sum(counts)
  return(total_count)
}

dummy <- c("🗑", "bogen", "😠", "👹", "💩", "baby", "und", "🆗")
count_hostile_emojis(dummy)
[1] 3
d_train %>% 
  mutate(hostile_emojis_n = map_int(tweet, count_hostile_emojis)) %>% 
  summarise(`Feindselige Emojis` = mean(hostile_emojis_n == 1))

Die Vermutung, dass Hate Speech feindselige Emojis enthält, stellt sich in diesem Fall als falsch heraus. Da es keinen einzigen Emoji dieser Art gibt, wird dieser Ansatz für die Modellierung verworfen.

3 Modellierung

3.1 Shallow-Learning

In der Modellierung ist es nun das Ziel, einen Algorithmus darauf zu trainieren, möglichst präzise Hate Speech vorherzusagen. Der Algorithmus meiner Wahl ist der XGBoost. Zunächst werden jedoch noch Rezepte formuliert, die die Erkenntnisse aus der Analyse nun in nützliche Features umwandeln.

3.1.1 Rezepte definieren

Rezept Eins enthält Schimpfwörter, Sentimentwerte und die Themenanalyse. Außerdem werden noch die üblichen Textverarbeitungsschritte durchgeführt sowie ein Tokenfilter angewandt.

rec1 <-
  recipe(class ~ ., data = d_train) %>% 
  step_text_normalization(tweet) %>%
  step_mutate(insult = get_sentiment(tweet,
                                       method = "custom",
                                       lexicon = insults)) %>% 
  step_mutate(senti = get_sentiment(tweet)) %>%
  step_tokenize(tweet, token = "words") %>%
  step_tokenfilter(tweet, max_tokens = 1e2) %>%
  step_stopwords(tweet, language = "en", stopword_source = "snowball") %>%
  step_stem() %>% 
  step_lda(tweet, num_topics = 6)

Rezept Zwei enthält statt der Themenanalyse die Tf-idf-Maße.

rec2 <-
  recipe(class ~ ., data = d_train) %>%
  update_role(id, new_role = "id") %>% 
  step_text_normalization(tweet) %>%
  step_mutate(insult = get_sentiment(tweet,
                                       method = "custom",
                                       lexicon = insults)) %>% 
  step_mutate(senti = get_sentiment(tweet)) %>% 
  step_tokenize(tweet, token = "words") %>%
  step_tokenfilter(tweet, max_tokens = 1e2) %>%
  step_stopwords(tweet, language = "en", stopword_source = "snowball") %>%
  step_stem() %>% 
  step_tfidf(tweet)
baked <- rec1 %>% 
  prep() %>% 
  bake(new_data = NULL)
baked
baked2 <- rec2 %>% 
  prep() %>% 
  bake(new_data = NULL)
baked2

3.1.2 Modell definieren

xgb <- 
  boost_tree(
  mtry = tune(), 
  trees = tune(), 
  tree_depth = tune(), 
  learn_rate = tune(), 
  min_n = tune(), 
  loss_reduction = tune()
  ) %>%
  set_engine("xgboost") %>%
  set_mode("classification") %>%
  translate()

3.1.3 Workflowset

Das Modell wird getuned. Hierfür wird zweifache Kreuzvalidierung mit einer Wiederholung verwendet. Der geringe Performance-Zuwachs durch intensiveres Tuning mit mehr Folds und Wiederholungen würde in diesem Fall nicht die höhere Rechenzeit rechtfertigen.

preproc <- list(rec1 = rec1, rec2 = rec2)

models <- list(xgb = xgb)

all_workflows <- workflow_set(preproc, models)

model_set <-
all_workflows %>%
workflow_map(
  resamples = vfold_cv(d_train,
  v = 2, 
  repeats = 1,
  strata = class),
  grid = 7,
  seed = 42,
  verbose = TRUE, 
  control = control_resamples(save_pred = TRUE))
i 1 of 2 tuning:     rec1_xgb
i Creating pre-processing data to finalize unknown parameter: mtry
Warning: package 'stopwords' was built under R version 4.2.3
Warning: package 'SnowballC' was built under R version 4.2.3
Warning: package 'xgboost' was built under R version 4.2.3
✔ 1 of 2 tuning:     rec1_xgb (1m 15s)
i 2 of 2 tuning:     rec2_xgb
i Creating pre-processing data to finalize unknown parameter: mtry
✔ 2 of 2 tuning:     rec2_xgb (1m 31.2s)

3.1.4 Ergebnisse

tune::autoplot(model_set) +
  theme(legend.position = "bottom")

model_set %>% 
  collect_metrics() %>% 
  arrange(-mean)

Rezept Zwei hat besser abgeschnitten als Rezept Eins. Wählen wir nun das beste Modell aus und fitten es:

3.1.5 Finalisieren

best_model_params <- 
  extract_workflow_set_result(model_set, "rec2_xgb") %>% 
  select_best()
Warning: No value of `metric` was given; metric 'roc_auc' will be used.
best_wf <- 
all_workflows %>% 
  extract_workflow("rec2_xgb")

best_wf_finalized <- 
  best_wf %>% 
  finalize_workflow(best_model_params)

fit_final <- fit(best_wf_finalized, data = d_train)
fit_final %>% 
  extract_fit_parsnip() %>% 
  vip()

Die Analyse der wichtigsten Prädiktoren deckt sich mit den Erkenntnissen aus der EDA. Die mit Abstand wichtigsten Features sind die Beleidigungen und Sentimentwerte, während die Tf-idf-Maße von Beleidigungen ebenfalls viel zur Prediction beitragen.

wf_preds <-
  collect_predictions(model_set)

wf_preds %>%
  group_by(wflow_id) %>% 
  roc_curve(truth = class, `.pred_hate speech`) %>% 
  autoplot()

Die Performance im Train-Sample fällt sehr gut aus, da die Vorhersagen mit einer Genauigkeit von rund 90 Prozent sehr präzise sind.

3.1.6 Vorhersagen

preds <- predict(fit_final, d_test)
preds
d_test1 <-
  d_test %>%  
   bind_cols(preds) %>% 
  mutate(class = as.factor(class))
d_test1
my_metrics <- metric_set(accuracy, f_meas)
my_metrics(d_test1,
           truth = class,
           estimate = .pred_class)

Auch im Test-Sample bewährt sich das Modell mit einer sehr hohen Genauigkeit.

3.2 Klassifikation mit Transformer

Ein weiterer Ansatz zur Klassifikation von Hate Speech ist es, kein eigenes Modell zu trainieren, sondern Zero-Shot-Learning anzuwenden. Das ergibt natürlich am meisten Sinn mit einem sehr fortgeschrittenen und komplexen Transformer-Modell, das bereits auf die Erkennung von Hate Speech trainiert wurde. Im Folgenden wird daher das Modell roberta-hate-speech-dynabench-r4-target von Facebook, welches auf Huggingface verfügbar ist, um die Tweets nach Hate Speech zu klassifizieren. Hierzu wird der Befehl pipeline aus der transformers-Library von Huggingface genutzt, um das Modell zu laden und auf das Test-Sample anzuwenden.

library(reticulate)
Warning: package 'reticulate' was built under R version 4.2.3
use_virtualenv("C:/Users/rapha/venv")
from transformers import pipeline
import tensorflow as tf
classifier = pipeline("text-classification", model="facebook/roberta-hate-speech-dynabench-r4-target")
WARNING:tensorflow:From C:\Users\rapha\venv\Lib\site-packages\keras\src\backend.py:873: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.

Some weights of the PyTorch model were not used when initializing the TF 2.0 model TFRobertaForSequenceClassification: ['roberta.embeddings.position_ids']
- This IS expected if you are initializing TFRobertaForSequenceClassification from a PyTorch model trained on another task or with another architecture (e.g. initializing a TFBertForSequenceClassification model from a BertForPreTraining model).
- This IS NOT expected if you are initializing TFRobertaForSequenceClassification from a PyTorch model that you expect to be exactly identical (e.g. initializing a TFBertForSequenceClassification model from a BertForSequenceClassification model).
All the weights of TFRobertaForSequenceClassification were initialized from the PyTorch model.
If your task is similar to the task the model of the checkpoint was trained on, you can already use TFRobertaForSequenceClassification for predictions without further training.
tweets <- d_test$tweet
tweets = r.tweets
results = classifier(tweets)
result <- py$results
labels <- lapply(result, function(element) element$label)
tweets_hate <- cbind(d_test, pred = unlist(labels))
tweets_hate <- tweets_hate %>% 
  mutate(class = as.factor(class),
         pred = case_when(pred == "hate" ~ "hate speech",
            pred == "nothate" ~ "other"),
         pred = as.factor(pred))
my_metrics2 <- metric_set(accuracy, f_meas)
my_metrics2(tweets_hate,
           truth = class,
           estimate = pred)

Die Performance des Modells ist objektiv gesehen gut, verglichen mit dem XGBoost mit einer Minute Trainingszeit fällt sie jedoch mager aus.

3.3 Neuronales Netzwerk

Bisher wurde Hate Speech sowohl mit Hilfe eines auf den konkreten Daten trainierten Shallow-Learner als auch mit Hilfe eines vortrainierten Transformers klassifiziert. Im letzten Schritt dieses Posts sollen die Stärken dieser beiden Ansätze kombiniert werden, indem ein Deep-Learning-Algorithums, genauer gesagt ein Neuronales Netzwerk, auf den vorliegenden Daten trainiert wird. Das neuronale Netz verwendet ein vortrainiertes Wort-Einbettungsmodell mit 50 Dimensionen, das für die deutsche Sprache optimiert ist. Dieses Embedding-Modell ermöglicht es dem Netzwerk, semantische Repräsentationen der Wörter zu erlernen. Das Netzwerk besteht aus einer Eingabeschicht, die das Embedding-Modell enthält, gefolgt von einer vollständig verbundenen Schicht mit 32 Neuronen und einer Sigmoid-Aktivierungsfunktion. Weiterhin gibt es eine Schicht mit 24 Neuronen und einer ReLU-Aktivierung. Die Ausgabeschicht besteht aus einem einzelnen Neuron für binäre Klassifikation. Das Netzwerk wird mit dem Adam-Optimizer kompiliert und die binäre Kreuzentropie wird als Verlustfunktion verwendet. Die Accuracy wird als Metrik überwacht. Das Training erfolgt über 3 Epochen mit einer Batch-Größe von 48, wobei die Validierung anhand des Test-Samples durchgeführt wird.

import pandas as pd
import numpy as np
import tensorflow_hub as hub
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.metrics import accuracy_score
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import make_scorer
d_train = r.d_train
d_test = r.d_test

X_train = d_train["tweet"].values
X_test = d_test["tweet"].values
d_train["y"] = d_train["class"].map({"other" : 0, "hate speech" : 1})
y_train = d_train.loc[:, "y"].values

d_test["y"] = d_test["class"].map({"other" : 0, "hate speech" : 1})
y_test = d_test.loc[:, "y"].values
embedding = "https://tfhub.dev/google/nnlm-de-dim50/2"
hub_layer = hub.KerasLayer(embedding, input_shape=[],
                           dtype=tf.string, trainable=True)
tf.random.set_seed(42)
model = tf.keras.Sequential()
model.add(hub_layer)
model.add(tf.keras.layers.Dense(32, activation='sigmoid'))
model.add(tf.keras.layers.Dense(24, activation='relu'))
model.add(tf.keras.layers.Dense(1))
model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])
WARNING:tensorflow:From C:\Users\rapha\venv\Lib\site-packages\keras\src\optimizers\__init__.py:309: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.

WARNING:tensorflow:From C:\Users\rapha\venv\Lib\site-packages\keras\src\optimizers\__init__.py:309: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.
model.fit(X_train, y_train,
epochs=3,
batch_size=48,
validation_data=(X_test, y_test),
verbose = 1)
Epoch 1/3

 1/94 [..............................] - ETA: 2:17 - loss: 1.0055 - accuracy: 0.2500
 2/94 [..............................] - ETA: 1:08 - loss: 0.9941 - accuracy: 0.2396
 3/94 [..............................] - ETA: 43s - loss: 0.9701 - accuracy: 0.2500 
 4/94 [>.............................] - ETA: 35s - loss: 0.9375 - accuracy: 0.2760
 5/94 [>.............................] - ETA: 40s - loss: 0.9277 - accuracy: 0.2833
 6/94 [>.............................] - ETA: 37s - loss: 0.9264 - accuracy: 0.3229
 7/94 [=>............................] - ETA: 34s - loss: 0.9098 - accuracy: 0.3750
 8/94 [=>............................] - ETA: 31s - loss: 0.8973 - accuracy: 0.4245
 9/94 [=>............................] - ETA: 29s - loss: 0.8848 - accuracy: 0.4676
10/94 [==>...........................] - ETA: 28s - loss: 0.8702 - accuracy: 0.4917
11/94 [==>...........................] - ETA: 26s - loss: 0.8579 - accuracy: 0.5265
12/94 [==>...........................] - ETA: 25s - loss: 0.8456 - accuracy: 0.5451
13/94 [===>..........................] - ETA: 24s - loss: 0.8332 - accuracy: 0.5625
14/94 [===>..........................] - ETA: 24s - loss: 0.8219 - accuracy: 0.5759
15/94 [===>..........................] - ETA: 23s - loss: 0.8109 - accuracy: 0.5847
16/94 [====>.........................] - ETA: 22s - loss: 0.8012 - accuracy: 0.5938
17/94 [====>.........................] - ETA: 21s - loss: 0.7920 - accuracy: 0.6005
18/94 [====>.........................] - ETA: 21s - loss: 0.7836 - accuracy: 0.6053
19/94 [=====>........................] - ETA: 20s - loss: 0.7772 - accuracy: 0.6075
20/94 [=====>........................] - ETA: 20s - loss: 0.7696 - accuracy: 0.6125
21/94 [=====>........................] - ETA: 19s - loss: 0.7607 - accuracy: 0.6210
22/94 [======>.......................] - ETA: 19s - loss: 0.7528 - accuracy: 0.6269
23/94 [======>.......................] - ETA: 18s - loss: 0.7441 - accuracy: 0.6350
24/94 [======>.......................] - ETA: 18s - loss: 0.7391 - accuracy: 0.6372
25/94 [======>.......................] - ETA: 18s - loss: 0.7326 - accuracy: 0.6417
26/94 [=======>......................] - ETA: 17s - loss: 0.7306 - accuracy: 0.6394
27/94 [=======>......................] - ETA: 17s - loss: 0.7273 - accuracy: 0.6389
28/94 [=======>......................] - ETA: 17s - loss: 0.7213 - accuracy: 0.6436
29/94 [========>.....................] - ETA: 16s - loss: 0.7201 - accuracy: 0.6422
30/94 [========>.....................] - ETA: 16s - loss: 0.7127 - accuracy: 0.6486
31/94 [========>.....................] - ETA: 15s - loss: 0.7061 - accuracy: 0.6539
32/94 [=========>....................] - ETA: 15s - loss: 0.7009 - accuracy: 0.6576
33/94 [=========>....................] - ETA: 15s - loss: 0.6954 - accuracy: 0.6616
34/94 [=========>....................] - ETA: 15s - loss: 0.6937 - accuracy: 0.6618
35/94 [==========>...................] - ETA: 14s - loss: 0.6890 - accuracy: 0.6655
36/94 [==========>...................] - ETA: 14s - loss: 0.6849 - accuracy: 0.6684
37/94 [==========>...................] - ETA: 14s - loss: 0.6824 - accuracy: 0.6700
38/94 [===========>..................] - ETA: 13s - loss: 0.6769 - accuracy: 0.6743
39/94 [===========>..................] - ETA: 13s - loss: 0.6734 - accuracy: 0.6763
40/94 [===========>..................] - ETA: 13s - loss: 0.6692 - accuracy: 0.6792
41/94 [============>.................] - ETA: 12s - loss: 0.6656 - accuracy: 0.6814
42/94 [============>.................] - ETA: 12s - loss: 0.6608 - accuracy: 0.6850
43/94 [============>.................] - ETA: 12s - loss: 0.6609 - accuracy: 0.6841
44/94 [=============>................] - ETA: 12s - loss: 0.6590 - accuracy: 0.6851
45/94 [=============>................] - ETA: 11s - loss: 0.6572 - accuracy: 0.6856
46/94 [=============>................] - ETA: 11s - loss: 0.6552 - accuracy: 0.6870
47/94 [==============>...............] - ETA: 11s - loss: 0.6516 - accuracy: 0.6897
48/94 [==============>...............] - ETA: 11s - loss: 0.6489 - accuracy: 0.6914
49/94 [==============>...............] - ETA: 10s - loss: 0.6485 - accuracy: 0.6913
50/94 [==============>...............] - ETA: 10s - loss: 0.6467 - accuracy: 0.6925
51/94 [===============>..............] - ETA: 10s - loss: 0.6444 - accuracy: 0.6940
52/94 [===============>..............] - ETA: 10s - loss: 0.6421 - accuracy: 0.6955
53/94 [===============>..............] - ETA: 9s - loss: 0.6396 - accuracy: 0.6969 
54/94 [================>.............] - ETA: 9s - loss: 0.6390 - accuracy: 0.6971
55/94 [================>.............] - ETA: 9s - loss: 0.6406 - accuracy: 0.6955
56/94 [================>.............] - ETA: 9s - loss: 0.6405 - accuracy: 0.6949
57/94 [=================>............] - ETA: 8s - loss: 0.6372 - accuracy: 0.6974
58/94 [=================>............] - ETA: 8s - loss: 0.6351 - accuracy: 0.6990
59/94 [=================>............] - ETA: 8s - loss: 0.6336 - accuracy: 0.6999
60/94 [==================>...........] - ETA: 8s - loss: 0.6323 - accuracy: 0.7007
61/94 [==================>...........] - ETA: 7s - loss: 0.6304 - accuracy: 0.7022
62/94 [==================>...........] - ETA: 7s - loss: 0.6282 - accuracy: 0.7036
63/94 [===================>..........] - ETA: 7s - loss: 0.6289 - accuracy: 0.7027
64/94 [===================>..........] - ETA: 7s - loss: 0.6288 - accuracy: 0.7025
65/94 [===================>..........] - ETA: 6s - loss: 0.6281 - accuracy: 0.7029
66/94 [====================>.........] - ETA: 6s - loss: 0.6273 - accuracy: 0.7036
67/94 [====================>.........] - ETA: 6s - loss: 0.6262 - accuracy: 0.7040
68/94 [====================>.........] - ETA: 6s - loss: 0.6250 - accuracy: 0.7047
69/94 [=====================>........] - ETA: 5s - loss: 0.6241 - accuracy: 0.7053
70/94 [=====================>........] - ETA: 5s - loss: 0.6234 - accuracy: 0.7054
71/94 [=====================>........] - ETA: 5s - loss: 0.6224 - accuracy: 0.7057
72/94 [=====================>........] - ETA: 5s - loss: 0.6226 - accuracy: 0.7049
73/94 [======================>.......] - ETA: 4s - loss: 0.6212 - accuracy: 0.7058
74/94 [======================>.......] - ETA: 4s - loss: 0.6202 - accuracy: 0.7064
75/94 [======================>.......] - ETA: 4s - loss: 0.6202 - accuracy: 0.7061
76/94 [=======================>......] - ETA: 4s - loss: 0.6206 - accuracy: 0.7053
77/94 [=======================>......] - ETA: 4s - loss: 0.6205 - accuracy: 0.7051
78/94 [=======================>......] - ETA: 3s - loss: 0.6202 - accuracy: 0.7049
79/94 [========================>.....] - ETA: 3s - loss: 0.6191 - accuracy: 0.7054
80/94 [========================>.....] - ETA: 3s - loss: 0.6180 - accuracy: 0.7063
81/94 [========================>.....] - ETA: 3s - loss: 0.6160 - accuracy: 0.7081
82/94 [=========================>....] - ETA: 2s - loss: 0.6155 - accuracy: 0.7081
83/94 [=========================>....] - ETA: 2s - loss: 0.6146 - accuracy: 0.7086
84/94 [=========================>....] - ETA: 2s - loss: 0.6137 - accuracy: 0.7091
85/94 [==========================>...] - ETA: 2s - loss: 0.6124 - accuracy: 0.7100
86/94 [==========================>...] - ETA: 1s - loss: 0.6110 - accuracy: 0.7112
87/94 [==========================>...] - ETA: 1s - loss: 0.6108 - accuracy: 0.7110
88/94 [===========================>..] - ETA: 1s - loss: 0.6108 - accuracy: 0.7107
89/94 [===========================>..] - ETA: 1s - loss: 0.6091 - accuracy: 0.7121
90/94 [===========================>..] - ETA: 0s - loss: 0.6073 - accuracy: 0.7137
91/94 [============================>.] - ETA: 0s - loss: 0.6054 - accuracy: 0.7150
92/94 [============================>.] - ETA: 0s - loss: 0.6055 - accuracy: 0.7144
93/94 [============================>.] - ETA: 0s - loss: 0.6044 - accuracy: 0.7153
94/94 [==============================] - ETA: 0s - loss: 0.6039 - accuracy: 0.7157
94/94 [==============================] - 24s 242ms/step - loss: 0.6039 - accuracy: 0.7157 - val_loss: 0.5418 - val_accuracy: 0.7444
Epoch 2/3

 1/94 [..............................] - ETA: 20s - loss: 0.6215 - accuracy: 0.6458
 2/94 [..............................] - ETA: 19s - loss: 0.5817 - accuracy: 0.6875
 3/94 [..............................] - ETA: 20s - loss: 0.5782 - accuracy: 0.6944
 4/94 [>.............................] - ETA: 20s - loss: 0.5656 - accuracy: 0.7083
 5/94 [>.............................] - ETA: 20s - loss: 0.5602 - accuracy: 0.7125
 6/94 [>.............................] - ETA: 20s - loss: 0.5445 - accuracy: 0.7257
 7/94 [=>............................] - ETA: 20s - loss: 0.5387 - accuracy: 0.7321
 8/94 [=>............................] - ETA: 19s - loss: 0.5409 - accuracy: 0.7292
 9/94 [=>............................] - ETA: 19s - loss: 0.5535 - accuracy: 0.7199
10/94 [==>...........................] - ETA: 19s - loss: 0.5506 - accuracy: 0.7229
11/94 [==>...........................] - ETA: 19s - loss: 0.5415 - accuracy: 0.7311
12/94 [==>...........................] - ETA: 18s - loss: 0.5354 - accuracy: 0.7361
13/94 [===>..........................] - ETA: 18s - loss: 0.5428 - accuracy: 0.7292
14/94 [===>..........................] - ETA: 18s - loss: 0.5496 - accuracy: 0.7217
15/94 [===>..........................] - ETA: 18s - loss: 0.5407 - accuracy: 0.7306
16/94 [====>.........................] - ETA: 17s - loss: 0.5352 - accuracy: 0.7357
17/94 [====>.........................] - ETA: 17s - loss: 0.5285 - accuracy: 0.7426
18/94 [====>.........................] - ETA: 17s - loss: 0.5292 - accuracy: 0.7407
19/94 [=====>........................] - ETA: 17s - loss: 0.5362 - accuracy: 0.7346
20/94 [=====>........................] - ETA: 17s - loss: 0.5386 - accuracy: 0.7323
21/94 [=====>........................] - ETA: 16s - loss: 0.5357 - accuracy: 0.7341
22/94 [======>.......................] - ETA: 16s - loss: 0.5331 - accuracy: 0.7367
23/94 [======>.......................] - ETA: 16s - loss: 0.5288 - accuracy: 0.7400
24/94 [======>.......................] - ETA: 16s - loss: 0.5296 - accuracy: 0.7396
25/94 [======>.......................] - ETA: 15s - loss: 0.5254 - accuracy: 0.7433
26/94 [=======>......................] - ETA: 15s - loss: 0.5200 - accuracy: 0.7484
27/94 [=======>......................] - ETA: 15s - loss: 0.5196 - accuracy: 0.7485
28/94 [=======>......................] - ETA: 15s - loss: 0.5203 - accuracy: 0.7470
29/94 [========>.....................] - ETA: 15s - loss: 0.5208 - accuracy: 0.7457
30/94 [========>.....................] - ETA: 14s - loss: 0.5207 - accuracy: 0.7451
31/94 [========>.....................] - ETA: 14s - loss: 0.5196 - accuracy: 0.7460
32/94 [=========>....................] - ETA: 14s - loss: 0.5188 - accuracy: 0.7461
33/94 [=========>....................] - ETA: 14s - loss: 0.5202 - accuracy: 0.7443
34/94 [=========>....................] - ETA: 14s - loss: 0.5202 - accuracy: 0.7439
35/94 [==========>...................] - ETA: 13s - loss: 0.5189 - accuracy: 0.7440
36/94 [==========>...................] - ETA: 13s - loss: 0.5181 - accuracy: 0.7448
37/94 [==========>...................] - ETA: 13s - loss: 0.5138 - accuracy: 0.7483
38/94 [===========>..................] - ETA: 13s - loss: 0.5140 - accuracy: 0.7473
39/94 [===========>..................] - ETA: 12s - loss: 0.5136 - accuracy: 0.7468
40/94 [===========>..................] - ETA: 12s - loss: 0.5134 - accuracy: 0.7469
41/94 [============>.................] - ETA: 12s - loss: 0.5133 - accuracy: 0.7464
42/94 [============>.................] - ETA: 12s - loss: 0.5134 - accuracy: 0.7460
43/94 [============>.................] - ETA: 12s - loss: 0.5132 - accuracy: 0.7452
44/94 [=============>................] - ETA: 11s - loss: 0.5123 - accuracy: 0.7453
45/94 [=============>................] - ETA: 11s - loss: 0.5109 - accuracy: 0.7458
46/94 [=============>................] - ETA: 11s - loss: 0.5121 - accuracy: 0.7437
47/94 [==============>...............] - ETA: 11s - loss: 0.5108 - accuracy: 0.7438
48/94 [==============>...............] - ETA: 10s - loss: 0.5098 - accuracy: 0.7444
49/94 [==============>...............] - ETA: 10s - loss: 0.5090 - accuracy: 0.7445
50/94 [==============>...............] - ETA: 10s - loss: 0.5096 - accuracy: 0.7437
51/94 [===============>..............] - ETA: 10s - loss: 0.5103 - accuracy: 0.7422
52/94 [===============>..............] - ETA: 9s - loss: 0.5083 - accuracy: 0.7436 
53/94 [===============>..............] - ETA: 9s - loss: 0.5088 - accuracy: 0.7429
54/94 [================>.............] - ETA: 9s - loss: 0.5084 - accuracy: 0.7427
55/94 [================>.............] - ETA: 9s - loss: 0.5061 - accuracy: 0.7443
56/94 [================>.............] - ETA: 8s - loss: 0.5068 - accuracy: 0.7422
57/94 [=================>............] - ETA: 8s - loss: 0.5062 - accuracy: 0.7427
58/94 [=================>............] - ETA: 8s - loss: 0.5053 - accuracy: 0.7432
59/94 [=================>............] - ETA: 8s - loss: 0.5039 - accuracy: 0.7440
60/94 [==================>...........] - ETA: 8s - loss: 0.5037 - accuracy: 0.7434
61/94 [==================>...........] - ETA: 7s - loss: 0.5029 - accuracy: 0.7439
62/94 [==================>...........] - ETA: 7s - loss: 0.5019 - accuracy: 0.7440
63/94 [===================>..........] - ETA: 7s - loss: 0.5019 - accuracy: 0.7421
64/94 [===================>..........] - ETA: 7s - loss: 0.5013 - accuracy: 0.7425
65/94 [===================>..........] - ETA: 6s - loss: 0.4999 - accuracy: 0.7436
66/94 [====================>.........] - ETA: 6s - loss: 0.4988 - accuracy: 0.7440
67/94 [====================>.........] - ETA: 6s - loss: 0.4970 - accuracy: 0.7453
68/94 [====================>.........] - ETA: 6s - loss: 0.4967 - accuracy: 0.7442
69/94 [=====================>........] - ETA: 5s - loss: 0.4974 - accuracy: 0.7418
70/94 [=====================>........] - ETA: 5s - loss: 0.4964 - accuracy: 0.7423
71/94 [=====================>........] - ETA: 5s - loss: 0.4939 - accuracy: 0.7441
72/94 [=====================>........] - ETA: 5s - loss: 0.4938 - accuracy: 0.7436
73/94 [======================>.......] - ETA: 4s - loss: 0.4922 - accuracy: 0.7449
74/94 [======================>.......] - ETA: 4s - loss: 0.4928 - accuracy: 0.7435
75/94 [======================>.......] - ETA: 4s - loss: 0.4908 - accuracy: 0.7450
76/94 [=======================>......] - ETA: 4s - loss: 0.4889 - accuracy: 0.7467
77/94 [=======================>......] - ETA: 4s - loss: 0.4880 - accuracy: 0.7470
78/94 [=======================>......] - ETA: 3s - loss: 0.4875 - accuracy: 0.7471
79/94 [========================>.....] - ETA: 3s - loss: 0.4876 - accuracy: 0.7460
80/94 [========================>.....] - ETA: 3s - loss: 0.4873 - accuracy: 0.7456
81/94 [========================>.....] - ETA: 3s - loss: 0.4871 - accuracy: 0.7456
82/94 [=========================>....] - ETA: 2s - loss: 0.4850 - accuracy: 0.7472
83/94 [=========================>....] - ETA: 2s - loss: 0.4838 - accuracy: 0.7482
84/94 [=========================>....] - ETA: 2s - loss: 0.4835 - accuracy: 0.7478
85/94 [==========================>...] - ETA: 2s - loss: 0.4833 - accuracy: 0.7473
86/94 [==========================>...] - ETA: 1s - loss: 0.4815 - accuracy: 0.7476
87/94 [==========================>...] - ETA: 1s - loss: 0.4816 - accuracy: 0.7471
88/94 [===========================>..] - ETA: 1s - loss: 0.4807 - accuracy: 0.7469
89/94 [===========================>..] - ETA: 1s - loss: 0.4794 - accuracy: 0.7474
90/94 [===========================>..] - ETA: 0s - loss: 0.4789 - accuracy: 0.7472
91/94 [============================>.] - ETA: 0s - loss: 0.4786 - accuracy: 0.7470
92/94 [============================>.] - ETA: 0s - loss: 0.4782 - accuracy: 0.7466
93/94 [============================>.] - ETA: 0s - loss: 0.4766 - accuracy: 0.7475
94/94 [==============================] - ETA: 0s - loss: 0.4762 - accuracy: 0.7479
94/94 [==============================] - 23s 245ms/step - loss: 0.4762 - accuracy: 0.7479 - val_loss: 0.4208 - val_accuracy: 0.7712
Epoch 3/3

 1/94 [..............................] - ETA: 22s - loss: 0.3227 - accuracy: 0.8333
 2/94 [..............................] - ETA: 20s - loss: 0.3428 - accuracy: 0.8021
 3/94 [..............................] - ETA: 21s - loss: 0.3412 - accuracy: 0.8056
 4/94 [>.............................] - ETA: 21s - loss: 0.3389 - accuracy: 0.8073
 5/94 [>.............................] - ETA: 21s - loss: 0.3404 - accuracy: 0.7958
 6/94 [>.............................] - ETA: 21s - loss: 0.3527 - accuracy: 0.7882
 7/94 [=>............................] - ETA: 21s - loss: 0.3438 - accuracy: 0.8006
 8/94 [=>............................] - ETA: 21s - loss: 0.3502 - accuracy: 0.7943
 9/94 [=>............................] - ETA: 20s - loss: 0.3469 - accuracy: 0.8009
10/94 [==>...........................] - ETA: 20s - loss: 0.3406 - accuracy: 0.8083
11/94 [==>...........................] - ETA: 20s - loss: 0.3366 - accuracy: 0.8068
12/94 [==>...........................] - ETA: 20s - loss: 0.3341 - accuracy: 0.8108
13/94 [===>..........................] - ETA: 20s - loss: 0.3323 - accuracy: 0.8125
14/94 [===>..........................] - ETA: 19s - loss: 0.3327 - accuracy: 0.8125
15/94 [===>..........................] - ETA: 19s - loss: 0.3299 - accuracy: 0.8167
16/94 [====>.........................] - ETA: 19s - loss: 0.3246 - accuracy: 0.8203
17/94 [====>.........................] - ETA: 19s - loss: 0.3227 - accuracy: 0.8235
18/94 [====>.........................] - ETA: 18s - loss: 0.3232 - accuracy: 0.8241
19/94 [=====>........................] - ETA: 18s - loss: 0.3248 - accuracy: 0.8224
20/94 [=====>........................] - ETA: 18s - loss: 0.3228 - accuracy: 0.8250
21/94 [=====>........................] - ETA: 18s - loss: 0.3193 - accuracy: 0.8264
22/94 [======>.......................] - ETA: 17s - loss: 0.3154 - accuracy: 0.8305
23/94 [======>.......................] - ETA: 17s - loss: 0.3136 - accuracy: 0.8297
24/94 [======>.......................] - ETA: 17s - loss: 0.3116 - accuracy: 0.8316
25/94 [======>.......................] - ETA: 17s - loss: 0.3132 - accuracy: 0.8292
26/94 [=======>......................] - ETA: 16s - loss: 0.3118 - accuracy: 0.8301
27/94 [=======>......................] - ETA: 16s - loss: 0.3111 - accuracy: 0.8295
28/94 [=======>......................] - ETA: 16s - loss: 0.3135 - accuracy: 0.8266
29/94 [========>.....................] - ETA: 16s - loss: 0.3102 - accuracy: 0.8297
30/94 [========>.....................] - ETA: 15s - loss: 0.3115 - accuracy: 0.8271
31/94 [========>.....................] - ETA: 15s - loss: 0.3115 - accuracy: 0.8286
32/94 [=========>....................] - ETA: 15s - loss: 0.3076 - accuracy: 0.8320
33/94 [=========>....................] - ETA: 15s - loss: 0.3058 - accuracy: 0.8346
34/94 [=========>....................] - ETA: 14s - loss: 0.3048 - accuracy: 0.8370
35/94 [==========>...................] - ETA: 14s - loss: 0.3034 - accuracy: 0.8393
36/94 [==========>...................] - ETA: 14s - loss: 0.3014 - accuracy: 0.8414
37/94 [==========>...................] - ETA: 14s - loss: 0.2994 - accuracy: 0.8446
38/94 [===========>..................] - ETA: 13s - loss: 0.2986 - accuracy: 0.8443
39/94 [===========>..................] - ETA: 13s - loss: 0.2963 - accuracy: 0.8462
40/94 [===========>..................] - ETA: 13s - loss: 0.2952 - accuracy: 0.8469
41/94 [============>.................] - ETA: 13s - loss: 0.2949 - accuracy: 0.8460
42/94 [============>.................] - ETA: 12s - loss: 0.2930 - accuracy: 0.8472
43/94 [============>.................] - ETA: 12s - loss: 0.2942 - accuracy: 0.8469
44/94 [=============>................] - ETA: 12s - loss: 0.2948 - accuracy: 0.8466
45/94 [=============>................] - ETA: 12s - loss: 0.2936 - accuracy: 0.8477
46/94 [=============>................] - ETA: 11s - loss: 0.2924 - accuracy: 0.8478
47/94 [==============>...............] - ETA: 11s - loss: 0.2911 - accuracy: 0.8480
48/94 [==============>...............] - ETA: 11s - loss: 0.2902 - accuracy: 0.8485
49/94 [==============>...............] - ETA: 11s - loss: 0.2892 - accuracy: 0.8495
50/94 [==============>...............] - ETA: 10s - loss: 0.2894 - accuracy: 0.8487
51/94 [===============>..............] - ETA: 10s - loss: 0.2882 - accuracy: 0.8497
52/94 [===============>..............] - ETA: 10s - loss: 0.2883 - accuracy: 0.8494
53/94 [===============>..............] - ETA: 10s - loss: 0.2868 - accuracy: 0.8510
54/94 [================>.............] - ETA: 9s - loss: 0.2846 - accuracy: 0.8530 
55/94 [================>.............] - ETA: 9s - loss: 0.2834 - accuracy: 0.8534
56/94 [================>.............] - ETA: 9s - loss: 0.2834 - accuracy: 0.8542
57/94 [=================>............] - ETA: 9s - loss: 0.2849 - accuracy: 0.8534
58/94 [=================>............] - ETA: 8s - loss: 0.2835 - accuracy: 0.8542
59/94 [=================>............] - ETA: 8s - loss: 0.2826 - accuracy: 0.8545
60/94 [==================>...........] - ETA: 8s - loss: 0.2808 - accuracy: 0.8559
61/94 [==================>...........] - ETA: 8s - loss: 0.2801 - accuracy: 0.8562
62/94 [==================>...........] - ETA: 7s - loss: 0.2792 - accuracy: 0.8572
63/94 [===================>..........] - ETA: 7s - loss: 0.2790 - accuracy: 0.8565
64/94 [===================>..........] - ETA: 7s - loss: 0.2773 - accuracy: 0.8584
65/94 [===================>..........] - ETA: 7s - loss: 0.2757 - accuracy: 0.8599
66/94 [====================>.........] - ETA: 6s - loss: 0.2745 - accuracy: 0.8611
67/94 [====================>.........] - ETA: 6s - loss: 0.2750 - accuracy: 0.8610
68/94 [====================>.........] - ETA: 6s - loss: 0.2731 - accuracy: 0.8621
69/94 [=====================>........] - ETA: 6s - loss: 0.2737 - accuracy: 0.8617
70/94 [=====================>........] - ETA: 5s - loss: 0.2718 - accuracy: 0.8631
71/94 [=====================>........] - ETA: 5s - loss: 0.2707 - accuracy: 0.8638
72/94 [=====================>........] - ETA: 5s - loss: 0.2695 - accuracy: 0.8646
73/94 [======================>.......] - ETA: 5s - loss: 0.2690 - accuracy: 0.8647
74/94 [======================>.......] - ETA: 4s - loss: 0.2687 - accuracy: 0.8646
75/94 [======================>.......] - ETA: 4s - loss: 0.2675 - accuracy: 0.8656
76/94 [=======================>......] - ETA: 4s - loss: 0.2650 - accuracy: 0.8673
77/94 [=======================>......] - ETA: 4s - loss: 0.2630 - accuracy: 0.8688
78/94 [=======================>......] - ETA: 3s - loss: 0.2617 - accuracy: 0.8694
79/94 [========================>.....] - ETA: 3s - loss: 0.2610 - accuracy: 0.8697
80/94 [========================>.....] - ETA: 3s - loss: 0.2602 - accuracy: 0.8706
81/94 [========================>.....] - ETA: 3s - loss: 0.2598 - accuracy: 0.8704
82/94 [=========================>....] - ETA: 2s - loss: 0.2590 - accuracy: 0.8707
83/94 [=========================>....] - ETA: 2s - loss: 0.2590 - accuracy: 0.8707
84/94 [=========================>....] - ETA: 2s - loss: 0.2579 - accuracy: 0.8713
85/94 [==========================>...] - ETA: 2s - loss: 0.2566 - accuracy: 0.8721
86/94 [==========================>...] - ETA: 1s - loss: 0.2552 - accuracy: 0.8728
87/94 [==========================>...] - ETA: 1s - loss: 0.2539 - accuracy: 0.8738
88/94 [===========================>..] - ETA: 1s - loss: 0.2530 - accuracy: 0.8741
89/94 [===========================>..] - ETA: 1s - loss: 0.2529 - accuracy: 0.8736
90/94 [===========================>..] - ETA: 0s - loss: 0.2530 - accuracy: 0.8743
91/94 [============================>.] - ETA: 0s - loss: 0.2515 - accuracy: 0.8755
92/94 [============================>.] - ETA: 0s - loss: 0.2513 - accuracy: 0.8757
93/94 [============================>.] - ETA: 0s - loss: 0.2506 - accuracy: 0.8763
94/94 [==============================] - ETA: 0s - loss: 0.2507 - accuracy: 0.8762
94/94 [==============================] - 24s 254ms/step - loss: 0.2507 - accuracy: 0.8762 - val_loss: 0.3095 - val_accuracy: 0.8686
<keras.src.callbacks.History object at 0x0000022A33ACF810>

WARNING:tensorflow:From C:\Users\rapha\venv\Lib\site-packages\keras\src\utils\tf_utils.py:492: The name tf.ragged.RaggedTensorValue is deprecated. Please use tf.compat.v1.ragged.RaggedTensorValue instead.

WARNING:tensorflow:From C:\Users\rapha\venv\Lib\site-packages\keras\src\utils\tf_utils.py:492: The name tf.ragged.RaggedTensorValue is deprecated. Please use tf.compat.v1.ragged.RaggedTensorValue instead.

WARNING:tensorflow:From C:\Users\rapha\venv\Lib\site-packages\keras\src\engine\base_layer_utils.py:384: The name tf.executing_eagerly_outside_functions is deprecated. Please use tf.compat.v1.executing_eagerly_outside_functions instead.

WARNING:tensorflow:From C:\Users\rapha\venv\Lib\site-packages\keras\src\engine\base_layer_utils.py:384: The name tf.executing_eagerly_outside_functions is deprecated. Please use tf.compat.v1.executing_eagerly_outside_functions instead.
y_pred_probs = model.predict(X_test)

 1/35 [..............................] - ETA: 4s
 4/35 [==>...........................] - ETA: 0s
 8/35 [=====>........................] - ETA: 0s
12/35 [=========>....................] - ETA: 0s
15/35 [===========>..................] - ETA: 0s
19/35 [===============>..............] - ETA: 0s
23/35 [==================>...........] - ETA: 0s
26/35 [=====================>........] - ETA: 0s
30/35 [========================>.....] - ETA: 0s
34/35 [============================>.] - ETA: 0s
35/35 [==============================] - 1s 17ms/step
y_pred = (model.predict(X_test) > 0.5).astype("int32")

 1/35 [..............................] - ETA: 1s
 4/35 [==>...........................] - ETA: 0s
 8/35 [=====>........................] - ETA: 0s
11/35 [========>.....................] - ETA: 0s
15/35 [===========>..................] - ETA: 0s
18/35 [==============>...............] - ETA: 0s
22/35 [=================>............] - ETA: 0s
25/35 [====================>.........] - ETA: 0s
29/35 [=======================>......] - ETA: 0s
33/35 [===========================>..] - ETA: 0s
35/35 [==============================] - 1s 17ms/step
accuracy = accuracy_score(y_test, y_pred)
print(f"Test Accuracy: {accuracy}")
Test Accuracy: 0.868632707774799
from sklearn.metrics import confusion_matrix

conf_matrix = confusion_matrix(y_test, y_pred)
print("Confusion Matrix:")
Confusion Matrix:
print(conf_matrix)
[[817  16]
 [131 155]]

Das neuronale Netzwerk sagt das Train-Sample zwar perfekt vorher, hat jedoch vergleichsweise große Schwierigkeiten beim Test-Sample.

4 Fazit

Durch die explorative Datenanalyse war es möglich, einige relevante Charakteristika herauszuarbeiten, die Hate-Speech-Tweets klar von anderen Tweets abgrenzen. Hate Speech enthält nämlich einen großen Anteil an Beleidigungen und Schimpfwörtern sowie negativen Sentimenten. Diese Erkenntnisse waren für die Modellierung hilfreich, da es gelang, Features basierend auf der EDA zu generieren, die von hoher Relevanz für die Performance des Modells waren. Das Ziel der Modellierung war es, ein Modell zu trainieren, das Hate Speech in Tweets möglichst akkurat erkennt. Durch den kombinierten Ansatz aus Training und Deep Learning wurde dieses Ziel mit Erfolg erreicht, auch wenn die Deep Learning Modelle vergleichsweise schlecht abschnitten.